// Copyright 2013 Ronald Schlenker, www.technewlogic.de.
// 
// This file is part of Byond.
// 
// Byond is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
// 
// Byond is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with Byond.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;

namespace Byond.UIRuntime
{
	public sealed class UiBindingMarkupExtension : MarkupExtension
	{
		private static readonly List<UiBindingMarkupExtension> GlobalRegistrations
			= new List<UiBindingMarkupExtension>();

		public UiBindingMarkupExtension(string path)
		{
			BindingPath = path;
		}

		public string BindingPath { get; private set; }
		public IUiControl Parent { get; private set; }
		public PropertyInfo Property { get; private set; }

		public override object ProvideValue(IServiceProvider serviceProvider)
		{
			// is already initialized?
			if (Parent != null)
				throw new Exception("Should not occur...");

			try
			{
				var providerValuetarget = (IProvideValueTarget)serviceProvider
					.GetService(typeof(IProvideValueTarget));

				// IMP: Schauen, das dass auch immer so stimmt mit den Typen
				//if (!(providerValuetarget.TargetObject is Control))
				if (!(providerValuetarget.TargetObject is FrameworkElement))
				{
					throw new NotImplementedException();
					//// Wahrscheinlich wurde die MarkupExtension innerhalb eines
					//// ControlTemplate benutzt und TargetObject is SharedDp.
					//// http://social.msdn.microsoft.com/forums/en-US/wpf/thread/a9ead3d5-a4e4-4f9c-b507-b7a7d530c6a9
					//return this;
				}

				Parent = providerValuetarget.TargetObject as IUiControl;
				if (Parent == null)
					throw new Exception("UiBindingMarkupExtension can only be applied to properties of IUiControl.");

				var dependencyProperty = providerValuetarget.TargetProperty as DependencyProperty;
				Property = dependencyProperty != null
					? Parent.GetType().GetProperty(dependencyProperty.Name)
					: providerValuetarget.TargetProperty as PropertyInfo;

				RegisterMe();

				return Property.PropertyType.IsValueType
					? Activator.CreateInstance(Property.PropertyType)
					: null;
			}
			catch (Exception e)
			{
				Debug.WriteLine("Error in UI Binding: " + e);
				throw;
			}
		}

		private void RegisterMe()
		{
			// TODO: Weak geht nicht, weil die gleich collected werden.
			// Alternative (hack): Lease Time
			
			// clear
			//_globalRegistrations
			//    .Select(it => new { it, it.Target })
			//    .ToList()
			//    .Where(it => it.Target == null)
			//    .ToList()
			//    .ForEach(it => _globalRegistrations.Remove(it.it));
			//_globalRegistrations.Add(new WeakReference<UiBindingMarkupExtension>(this));
			GlobalRegistrations.Add(this);
		}

		public static IEnumerable<UiBindingMarkupExtension> GetRegistrations()
		{
			return GlobalRegistrations.ToList();
			//return _globalRegistrations
			//    .Select(it => it.Target)
			//    .ToList()
			//    .Where(it => it != null)
			//    .ToList();
		}

		public static void RemoveRegistration(IEnumerable<UiBindingMarkupExtension> registrations)
		{
			registrations.ForEach(it => GlobalRegistrations.Remove(it));
		}
	}
}